package com.ywz.common;


import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * 类描述 -> 树型集合工具类
 *
 * @Author: ywz
 * @Date: 2024/09/16
 */
@Slf4j
public class TreeListUtils {

    /**
     * 方法描述 -> 判断集合是否为空，适用于Collection及其子类
     *
     * @param collection -> 数据源
     * @Author: ywz
     * @Date: 2024/09/17
     */
    public static boolean isEmpty(Collection<?> collection) {
        return collection == null || collection.isEmpty();
    }

    /**
     * 方法描述 -> 将list转为树形结构
     *
     * @param list              -> 数据源
     * @param clazz             -> 数据源类型
     * @param idFieldName       -> id属性名
     * @param pidFieldName      -> 父id属性名
     * @param pidValue          -> 头部父id的值
     * @param childrenFieldName -> 子节点属性名
     * @Author: ywz
     * @Date: 2024/09/16
     */
    public static <T> List<T> listToTree(List<T> list, Class<T> clazz, String idFieldName, String pidFieldName, Object pidValue, String childrenFieldName) {
        // 判断数据源是否为空
        if (isEmpty(list)) {
            log.error("数据源为空");
            return list;
        }
        if (StringUtils.isNull(clazz, idFieldName, pidFieldName, pidValue, childrenFieldName)) {
            log.error("参数为空");
            return list;
        }
        // 获取pid属性、id属性、children属性
        Field declaredField = null;
        Field idField = null;
        Field childrenField = null;
        try {
            declaredField = clazz.getDeclaredField(pidFieldName);
            idField = clazz.getDeclaredField(idFieldName);
            childrenField = clazz.getDeclaredField(childrenFieldName);
        } catch (NoSuchFieldException e) {
            log.error("pidFieldName、pidFieldName、childrenFieldName属性不存在");
            return list;
        }

        declaredField.setAccessible(true);
        idField.setAccessible(true);
        childrenField.setAccessible(true);

        // 创建返回的结果集对象
        List<T> resultList = new ArrayList<>();
        for (T t : list) {
            // 获取头部对象
            try {
                if (declaredField.get(t).equals(pidValue)) {
                    // 获取id值
                    Object o = idField.get(t);
                    // 将id作为pid的值，获取子节点列表
                    List<T> ts = checkList(list, clazz, pidFieldName, o);
                    // 如果有子节点，则继续递归
                    if (!ts.isEmpty())
                        listToTree(list, clazz, idFieldName, pidFieldName, o, childrenFieldName);
                    // 将子节点列表赋值给children属性
                    childrenField.set(t, ts);
                    // 将对象装入结果集中
                    resultList.add(t);
                }
            } catch (IllegalAccessException e) {
                log.error("获取属性值失败，请确保开启private属性访问权限");
                return list;
            }
        }
        return resultList;
    }

    /**
     * 方法描述 -> 将树形结构转为list
     *
     * @param treeList          -> 数据源
     * @param clazz             -> 数据源类型
     * @param childrenFieldName -> 子节点属性名
     * @Author: ywz
     * @Date: 2024/09/17
     */
    @SuppressWarnings("unchecked")
    public static <T> List<T> treeToList(List<T> treeList, Class<T> clazz, String childrenFieldName) {
        if (isEmpty(treeList)) {
            return treeList;
        }
        if (StringUtils.isNull(clazz, childrenFieldName)) {
            log.error("参数为空");
            return treeList;
        }
        Field declaredField = null;
        try {
            declaredField = clazz.getDeclaredField(childrenFieldName);
        } catch (NoSuchFieldException e) {
            log.error("childrenFieldName属性不存在");
            return treeList;
        }
        declaredField.setAccessible(true);
        List<T> resultList = new ArrayList<>();
        for (T t : treeList) {
            // 如果子节点不为空，则继续递归
            Object o = null;
            try {
                o = declaredField.get(t);
            } catch (IllegalAccessException e) {
                log.error("获取属性值失败，请确保开启private属性访问权限");
                return treeList;
            }
            if (o instanceof List) {
                List<T> ts = (List<T>) o;
                resultList.addAll(treeToList(ts, clazz, childrenFieldName));
            }
            resultList.add(t);
        }
        return resultList;
    }

    /**
     * 方法描述 -> 根据指定的属性值给对象排名，并设置指定排名属性的值（倒序）
     *
     * @param list -> 数据源
     * @param clazz -> 数据源类型
     * @param byField -> 依据字段
     * @param rankingField -> 排名字段
     * @Author: ywz
     * @Date: 2024/10/28
     */
    public static <T> List<T> rankingListByField(List<T> list, Class<T> clazz, String byField, String rankingField) {
        if (isEmpty(list)) {
            log.error("数据源为空");
            return list;
        }
        if (StringUtils.isNull(clazz, byField, rankingField)) {
            log.error("参数为空");
            return list;
        }
        // 获取字段
        Field declaredByField = null;
        Field declaredRankingField = null;
        try {
            declaredByField = clazz.getDeclaredField(byField);
            declaredRankingField = clazz.getDeclaredField(rankingField);
        } catch (NoSuchFieldException e) {
            log.error("byField、rankingField字段不存在");
            return list;
        }

        declaredByField.setAccessible(true);
        declaredRankingField.setAccessible(true);
        // 检查字段类型
        Class<?> declaredByFieldType = declaredByField.getType();
        if (!declaredByFieldType.equals(Integer.class)
                && !declaredByFieldType.equals(Long.class)
                && !declaredByFieldType.equals(Double.class)
                && !declaredByFieldType.equals(BigDecimal.class)) {
            log.error("依据字段类型错误，请保证依据字段为Integer、Long、Double、BigDecimal四个类型之一");
            return list;
        }
        Class<?> declaredRankingFieldType = declaredRankingField.getType();
        if (!declaredRankingFieldType.equals(Integer.class) && !declaredRankingFieldType.equals(int.class)) {
            log.error("排名字段类型错误，请保证排名字段为int或integer类型");
            return list;
        }

        // 倒序排列
        Field finalDeclaredByField = declaredByField;
        list.sort((t1, t2) -> {
            try {
                if (declaredByFieldType.equals(BigDecimal.class))
                    return ((BigDecimal) finalDeclaredByField.get(t2)).compareTo((BigDecimal) finalDeclaredByField.get(t1));
                else {
                    double i = ((Number) finalDeclaredByField.get(t2)).doubleValue();
                    double j = ((Number) finalDeclaredByField.get(t1)).doubleValue();
                    return Double.compare(i, j);
                }
            } catch (IllegalAccessException e) {
                log.error("获取属性值失败");
                return 0;
            }
        });

        // ========================设置排名=========================
        AtomicInteger ranking = new AtomicInteger(1);
        // 排名相同的个数
        AtomicInteger count = new AtomicInteger();
        // 上一个值
        AtomicReference<BigDecimal> previousPerformanceRateValue; // bigDecimal类型
        AtomicReference<Double> previousPerformanceRateValueDouble = new AtomicReference<>(); // 其他类型
        if (declaredByFieldType.equals(BigDecimal.class)) {
            previousPerformanceRateValue = new AtomicReference<>();
            try {
                previousPerformanceRateValue.set((BigDecimal) declaredByField.get(list.get(0)));
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        } else {
            previousPerformanceRateValue = null;
            try {
                previousPerformanceRateValueDouble.set(((Number) declaredByField.get(list.get(0))).doubleValue());
            } catch (IllegalAccessException e) {
                log.error("获取属性值失败");
                return list;
            }
        }

        Field finalDeclaredByField1 = declaredByField;
        Field finalDeclaredRankingField = declaredRankingField;

        list.forEach(item -> {
            if (declaredByFieldType.equals(BigDecimal.class)) {
                // 依据字段类型为BigDecimal
                try {
                    BigDecimal itemValue = (BigDecimal) finalDeclaredByField1.get(item);
                    if (itemValue.compareTo(previousPerformanceRateValue.get()) == 0) {
                        count.getAndIncrement();
                    } else {
                        ranking.set(ranking.get() + count.get());
                        count.set(1);
                        previousPerformanceRateValue.set(itemValue);
                    }
                } catch (IllegalAccessException e) {
                    log.error("获取属性值失败");
                    return;
                }
            } else {
                // 依据字段类型为其他类型
                try {
                    Number itemNumberValue = (Number) finalDeclaredByField1.get(item);
                    Double itemValue = itemNumberValue.doubleValue();
                    if (itemValue.compareTo(previousPerformanceRateValueDouble.get()) == 0) {
                        count.getAndIncrement();
                    } else {
                        ranking.set(ranking.get() + count.get());
                        count.set(1);
                        previousPerformanceRateValueDouble.set(itemValue);
                    }
                } catch (IllegalAccessException e) {
                    log.error("获取属性值失败");
                    return;
                }
            }
            // 赋值排名
            try {
                finalDeclaredRankingField.set(item, ranking.get());
            } catch (IllegalAccessException e) {
                log.error("获取属性值失败");
            }
        });
        return list;
    }


    /**
     * 方法描述 -> 判断Tree集合中对象的属性是否包含指定的值
     *
     * @param list -> 数据源
     * @param clazz -> 数据源类型
     * @param fieldName -> 指定的字段名
     * @param value -> 指定的值
     * @param childrenFieldName -> 子节点属性名
     * @Author: ywz
     * @Date: 2024/12/31
     */
    @SuppressWarnings("unchecked")
    public static <T> boolean isExistsFieldValue(List<T> list, Class<T> clazz, String fieldName, Object value, String childrenFieldName) {
        // 结束递归的条件
        if (isEmpty(list))
            return false;

        if (StringUtils.isNull(fieldName, value)) {
            log.error("参数为空");
            return false;
        }
        try {
            Field nameField = clazz.getDeclaredField(fieldName);
            Field childrenField = clazz.getDeclaredField(childrenFieldName);
            nameField.setAccessible(true);
            childrenField.setAccessible(true);
            for (T t : list) {
                if (nameField.get(t).equals(value))
                    return true;
                if (childrenField.get(t) instanceof List) {
                    List<T> childrenList = (List<T>) childrenField.get(t);
                    if (isExistsFieldValue(childrenList, clazz, fieldName, value, childrenFieldName))
                        return true;
                }
            }
        } catch (NoSuchFieldException e) {
            log.error("获取属性失败");
        } catch (IllegalAccessException e) {
            log.error("获取属性值失败");
        }
        return false;
    }

    /**
     * 方法描述 -> 判断Tree集合中对象的属性是否包含指定的值
     *
     * @param list -> 数据源
     * @param clazz -> 数据源类型
     * @param fieldName -> 指定的字段名
     * @param value -> 指定的值
     * @param childrenFieldName -> 子节点属性名
     * @Author: ywz
     * @Date: 2024/12/31
     */
    @SuppressWarnings("unchecked")
    public static <T> T filterTreeByExistsFieldValue(List<T> list, Class<T> clazz, String fieldName, Object value, String childrenFieldName) {
        // 结束递归的条件
        if (isEmpty(list))
            return null;

        if (StringUtils.isNull(fieldName, value)) {
            log.error("参数为空");
            return null;
        }
        try {
            Field nameField = clazz.getDeclaredField(fieldName);
            Field childrenField = clazz.getDeclaredField(childrenFieldName);
            nameField.setAccessible(true);
            childrenField.setAccessible(true);
            for (T t : list) {
                if (nameField.get(t).equals(value))
                    return t;
                if (childrenField.get(t) instanceof List) {
                    List<T> childrenList = (List<T>) childrenField.get(t);
                    // 递归调用子节点
                    T t1 = filterTreeByExistsFieldValue(childrenList, clazz, fieldName, value, childrenFieldName);
                    if (t1 != null)
                        return t1;
                }
            }
        } catch (NoSuchFieldException e) {
            log.error("获取属性失败");
        } catch (IllegalAccessException e) {
            log.error("获取属性值失败");
        }
        return null;
    }

    /**
     * 方法描述 -> 检查集合中指定字段符合指定的值的对象，并将其返回。
     * 内部方法使用，具体的集合请直接使用stream()方法。
     *
     * @param list         -> 数据源
     * @param clazz        -> 数据源类型
     * @param fieldName -> 指定的字段名
     * @param value     -> 指定的值
     * @Author: ywz
     * @Date: 2024/09/16
     */
    private static <T> List<T> checkList(List<T> list, Class<T> clazz, String fieldName, Object value) {
        return list.stream().filter(t -> {
            try {
                Field declaredField = clazz.getDeclaredField(fieldName);
                declaredField.setAccessible(true);
                if (declaredField.get(t).equals(value)) {
                    return true;
                }
            } catch (NoSuchFieldException | IllegalAccessException e) {
                log.error("字段不存在、获取属性值失败");
                return false;
            }
            return false;
        }).collect(Collectors.toList());
    }

}
